build: run the declaration-import gate in strict mode; close the zod and typescript-5 declaration leaks - #586
Conversation
…od / typescript-5 declaration leaks - events/ipc.ts derives EventRuntimeAvailability from a const tuple instead of z.infer, so dist/events/ipc.d.ts no longer imports zod. - routes/syntax.ts owns the TypeScript-AST helpers the static route extractors share (unwrapExpression, positionOf, hasExportModifier) behind structural node types; input-schema.ts keeps its zod-chain grammar module-private, so dist/routes/input-schema.d.ts no longer imports typescript-5. - lint:release passes --strict to scripts/check-declaration-imports.mjs: every packed declaration, internal or reachable, must resolve for a consumer. - Preview docs: pnpm 11 blockExoticSubdeps caveat for the rewritten @agent-bundle/runtime -> rsc-markdown-stream preview dependency.
🦋 Changeset detectedLatest commit: 591be33 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 95625585ad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
pnpm lint:releasenow runsscripts/check-declaration-imports.mjs --strict(#568, #571) over theagent-bundle,@agent-bundle/runtime,rsc-markdown-stream, andcreate-agent-bundletarballs, so a devDependency or undeclared package imported from any packed.d.ts— internal declarations included — fails the gate instead of printing a warning. The two internal leaks that madeagent-bundlewarn are closed at the source, and the preview docs gain the pnpm 11blockExoticSubdepscaveat.The two leaks
dist/events/ipc.d.ts→zodexport type EventRuntimeAvailability = z.infer<typeof runtimeAvailabilitySchema>derived a public type from a non-exported zod schema, so the emitter had to shipdeclare const runtimeAvailabilitySchema: z.ZodEnum<…>plusimport { z } from 'zod'.Fix —
packages/agent-bundle/src/events/ipc.ts:76-84: the tuple is the single source; the type is derived from the tuple and the schema is built from it.EventRuntimeAvailabilityresolves to the identical three-member union; thezodimport stays a runtime import for wire parsing and no longer appears in the declaration.dist/routes/input-schema.d.ts→typescript-5Eight exports of
src/routes/input-schema.tsnamedts.Expression/ts.Node/ts.SourceFile/ts.Statementin their signatures (ChainCall,ZodChain,unwrapExpression,positionOf,flattenZodChain,staticLiteral,scalarBaseOf,hasExportModifier). Only three of them had another importer (config-extract.ts:unwrapExpression,positionOf,hasExportModifier).Fix:
packages/agent-bundle/src/routes/syntax.tsowns the three shared helpers (unwrapExpression:54,positionOf:61,hasExportModifier:67) typed against small structural interfaces (SyntaxNode,SyntaxSourceFile,SyntaxStatement, :15-28) that everyts.Nodesatisfies. The implementation still uses the bundled compiler (ts.SyntaxKindvalues), but nots.*type reaches an exported signature, so the emittedsyntax.d.tshas no imports at all.unwrapExpressionis generic in the argument type (<Expression extends SyntaxNode>(e: Expression) => Expression) — exact forts.Expression, safe for its brand-only families, documented not to be given a wrapper type.input-schema.ts:6andconfig-extract.ts:12import the trio from./syntax.ts(extract-and-rewire in one change;config-extractno longer depends oninput-schema).input-schema.ts(ChainCall:17,ZodChain:23,flattenZodChain:57,staticLiteral:77,scalarBaseOf:138) had no importer outside the module and is now module-private, so itsts.*types stop reaching the declaration. Its public surface (parseInputSchema,extractInputSchema,StaticInputSchemaProperty,ParsedInputSchema*,ScalarBase*,validationOnlyMethods) is unchanged.stripInternalwas considered and rejected:src/already carries@internalJSDoc on public test seams (dev/epoch-store.ts,dev/workbench-server.ts, …) that must stay in the shipped declarations.Checker output
Before (
node scripts/check-declaration-imports.mjs <4 packages>):After (
pnpm lint:release, i.e.--strict):(334 = 333 + the new
dist/routes/syntax.d.ts.)Gate flip and prose
package.jsonlint:release:node scripts/check-declaration-imports.mjs --strict …(one invocation covers all four packages).scripts/check-declaration-imports.mjsheader andpackages/agent-bundle/rslib.config.tscomment now describe the strict gate. The.d.mtstwin is unchanged (no API change);tests/check-declaration-imports.test.tspasses.website/docs/{en,zh}/guide/distribution/preview-packages.mdx: the sentence that saidlint:releasedoes not pass--strictnow says it does.docs/preview-packages.mdnever described the check.Docs caveat: pnpm 11 and the rewritten preview dependency
pkg.pr.new rewrites
@agent-bundle/runtime→rsc-markdown-streamto the renderer's same-sha preview tarball URL. pnpm 11'sblockExoticSubdeps(defaulttrue, verified against https://pnpm.io/settings/dependency-resolution) rejects a transitive tarball-URL dependency withERR_PNPM_EXOTIC_SUBDEP. One paragraph indocs/preview-packages.mdand in both locales ofguide/distribution/preview-packages.mdx, at the point where the rewrite is described: setblockExoticSubdeps: falsein the consuming project'spnpm-workspace.yaml, or install previews with npm.Verification
On the branch merged with
origin/main(includes #575 Rslib 1.0 / Rsbuild 2.2 and #583):pnpm install --frozen-lockfile && pnpm build,pnpm typecheck,pnpm lint,pnpm test:unit,pnpm lint:release(strict, 0 errors / 0 warnings on all four tarballs),pnpm docs:site:build(dead-link and language-parity checks pass).Self-review
Reviewer:
change-risk-reviewersubagent, modelgpt-5.6-sol-medium, run against the branch (merged withorigin/main) vsorigin/main, asked for concrete merge risks only and specifically whether any public type changed shape. Verdict: no concrete merge risks; six areas checked, all no-risk:exportstypestarget re-exportsevents/ipc.ts,routes/input-schema.ts, orroutes/syntax.ts;EventRuntimeAvailabilityis the same three-literal union (dist/events/ipc.d.ts:6-13). Disposition: confirmed, nothing to fix.syntax.tspeels exactly TS 5.9's five wrapper kinds (TypeAssertionExpressionconfirmed attypescript.d.ts:3896); directmodifiersscanning is equivalent tocanHaveModifiers/getModifiersfor variable/function/class statements, decorators andexport defaultincluded; allunwrapExpressioncall sites pass expression-family types. Disposition: confirmed.z.enumacceptsconst T extends readonly string[]and yields the same union; embedded strict schemas andEventRuntimeStatusResultunchanged. Disposition: confirmed.syntax.tsis reached from production code throughinput-schema.ts→routes/graph.ts/routes/cli-argv.tsandconfig-extract.ts; no remaining importer of the five privatized helpers anywhere (tests included). Disposition: confirmed.parseArgumentsaccepts a leading--strict; the existing test already exercises['--strict', root]; the.d.mtsAPI is unchanged; PR CI runscheck:release:ci(.github/workflows/ci.yml:294-313), nightly/release runcheck:release, so the strict gate runs in CI — and did: the "Release gates" check on this PR is green. Disposition: confirmed.blockExoticSubdepsdefaulttrue,pnpm-workspace.yaml,ERR_PNPM_EXOTIC_SUBDEP); en/zh parity holds; no stale--strict/lint:releaseprose remains; oneagent-bundle: patchchangeset ending in(#586). Disposition: confirmed.No fixes resulted from the self-review, so no second reviewer pass was needed.
Codex review thread (on the pre-
(#586)commit9562558): "Add the PR number to the changeset summary" — fixed in473f65d60, replied and resolved.